﻿log("Initializing Utilities ...");
;
// ------------------------
// Utilities
// ------------------------
doNothing = function () { }
functionWithSizzle = function functionWithSizzle(doWhat)
{
    var n = arguments.length;
    var args = new Array(n + 1);
    args[0] = "./sizzle.min.js";
    for (var i = 0; i < n; ++i)
    {
        args[i + 1] = arguments[i];
    }
    return functionWithScript.apply(null, args);
}
doWithSizzle = function doWithSizzle(onLoaded)
{
    var n = arguments.length;
    var args = new Array(n + 1);
    args[0] = "./sizzle.min.js";
    for (var i = 0; i < n; ++i)
    {
        args[i + 1] = arguments[i];
    }
    return doWithScript.apply(null, args);
}
functionWithJQuery = function functionWithJQuery(doWhat)
{
    var n = arguments.length;
    var args = new Array(n + 1);
    args[0] = "./jquery-2.1.4.min.js";
    for (var i = 0; i < n; ++i)
    {
        args[i + 1] = arguments[i];
    }
    return functionWithScript.apply(null, args);
}
doWithJQuery = function doWithJQuery(onLoaded)
{
    var n = arguments.length;
    var args = new Array(n + 1);
    args[0] = "./jquery-2.1.4.min.js";
    for (var i = 0; i < n; ++i)
    {
        args[i + 1] = arguments[i];
    }
    return doWithScript.apply(null, args);
}

functionWithScript = function functionWithScript(script, doWhat)
{
    var n = arguments.length;
    var bindings = new Array(n - 2);
    for (var i = 0; i < n - 2; ++i)
    {
        bindings[i] = arguments[i + 2];
    }
    return function ()
    {
        var s = bindings.length;
        var n = arguments.length;
        for (var i = 0; i < n; ++i)
        {
            bindings[i + s] = arguments[i];
        }
        loadScriptAsync(script, function ()
        {
            doWhat.apply(null, bindings);
        });
    }
}
doWithScript = function doWithScript(script, onLoaded)
{
    var n = arguments.length;
    var args = new Array(n - 2);
    for (var i = 0; i < n - 2; ++i)
    {
        args[i] = arguments[i + 2];
    }
    loadScriptAsync(script, function ()
    {
        onLoaded.apply(null, args);
    });
}

waitForLoaded = function waitForLoaded(onLoaded)
{
    var currentLocation = location.href;
    checkLoop();
    function checkLoop()
    {
        if (location.href === currentLocation)
            setTimeout(checkLoop, 0);
        else
            onLoaded();
    }
};
parseUrl = function parseUrl(url)
{
    var a = document.createElement('a');
    a.href = url;
    return {
        source: url,
        protocol: a.protocol.replace(':', ''),
        host: a.hostname,
        port: a.port,
        query: a.search,
        params: (function ()
        {
            var ret = {},
            seg = a.search.replace(/^\?/, '').split('&'),
            len = seg.length, i = 0, s;
            for (; i < len; i++)
            {
                if (!seg[i]) { continue; }
                s = seg[i].split('=');
                ret[s[0]] = s[1];
            }
            return ret;
        })(),
        file: (a.pathname.match(/\/([^\/?#]+)$/i) || [, ''])[1],
        hash: a.hash.replace('#', ''),
        path: a.pathname.replace(/^([^\/])/, '/$1'),
        relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [, ''])[1],
        segments: a.pathname.replace(/^\//, '').split('/')
    };
}
waitForLoaded = function waitForLoaded(onFinished, arg)
{
    var currentLocation = location.href;

    var n = arguments.length;
    var args = new Array(n - 1);
    for (var i = 0; i < n; ++i)
    {
        args[i] = arguments[i + 1];
    }
    internalWaitForLoaded();

    function internalWaitForLoaded()
    {
        if (location.href === currentLocation)
            setTimeout(internalWaitForLoaded, 1);
        else
            setTimeout(function ()
            {
                onFinished.apply(null, args);
            }, 100, arg);
    }
};

// ---------------------------------------------
// Simulator
// ---------------------------------------------
simulateMouseDownOnObject = function simulateMouseDownOnObject(obj)
{
    simulateWithTypeName("mousedown");
    simulateWithTypeName("mouseup");
    function simulateWithTypeName(typeName)
    {
        var evt = document.createEvent("MouseEvents");
        evt.initMouseEvent(typeName,                        // event
            true, true,                                     // bubble / cancle
            document.defaultView, 1,                                        // item, detail
            0, 0,                                           // screenx, screeny
            0, 0,    // clientx, clienty
            //obj.offsetWidth / 2, obj.offsetHeight / 2,    // clientx, clienty
            false, false, false, false, 0, obj);            // alt, ctrl and so on.
        obj.dispatchEvent(evt);
    }
}




// -----------------------
// Time and Animation
// -----------------------

// 
/*! Animate a action
 * this is a async version of animate
 * @param arg.starts an array of start status
 * @param arg.ends an array of end status
 * @param arg.firstVariableStep increasement of starts[0]
 * @param arg.duraction
 * @param arg.stepInterval
 * @param arg.stepCallback
 * @param arg.onFinished
 * @note you must privide excetly two param among \a firstVariableStep, \a duraction and \a stepInterval
    if you provide all three of them, only duraction and stepInterval is used.
 */
animateAsync = function animateAsync(arg)
{
    var starts = arg.starts;
    var ends = arg.ends;
    var firstVariableStep = arg.firstVariableStep;
    var duraction = arg.duraction;
    var stepInterval = arg.stepInterval;
    var stepCallback = arg.stepCallback;
    var onFinished = arg.onFinished;
    if (!firstVariableStep)
        ; // just ok, we needn't it
    if (!duraction)
        duraction = Math.abs((ends[0] - starts[0]) / firstVariableStep * stepInterval);
    if (!stepInterval)
        stepInterval = duraction / (ends[0] - starts[0]) * firstVariableStep;

    calc(starts, ends, new Date(), stepCallback, onFinished, stepInterval);
    function calc(starts, ends, startTime, stepCallback, onFinished, stepInterval)
    {
        var pos = (new Date() - startTime) / duraction;
        var cur = {}
        for (var i in starts)
        {
            cur[i] = (ends[i] - starts[i]) * pos + starts[i];
        }
        if (pos < 1)
        {
            stepCallback(cur);
            setTimeout(calc, stepInterval, starts, ends, startTime, stepCallback, onFinished, stepInterval);
        }
        else //if (pos >= 1)
        {
            pos = 1;
            stepCallback(cur);
            if (onFinished)
                setTimeout(onFinished, 0);
        }
    }
}
smoothScrollTo = function smoothScrollTo(y, onFinished, secondsPerScreen)
{
    animateAsync(
        {
            starts: [window.scrollY],
            ends: [y],
            firstVariableStep: window.innerHeight * 3 / 4,
            stepInterval: secondsPerScreen && secondsPerScreen * 3 / 4 * 1000 || 300,
            stepCallback: function (cur)
            {
                window.scroll(0, cur[0]);
            },
            onFinished: function ()
            {
                setTimeout(onFinished, 1000)
            }
        });
}